﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SlimDX.Direct3D9;
using SlimDX;
using System.Drawing;
using LibRadiant.Experimental;
using LibRadiant.IO;

namespace LibRadiant.Main
{
    public delegate void PreRender(double inDelta);
    public delegate void Render(double inDelta);
    public delegate void PostRender(double inDelta);
    public delegate void InitHandler();

	public class D3D9Core
	{
        public event PreRender OnPreRender;
        public event Render OnRender;
        public event PostRender OnPostRender;       

		private Direct3D mD3D;
        private Device mD3DDevice;
        public Device D3DDevice
        {
            get { return mD3DDevice; }
        }

        private IOManager mIOManager;
        public IOManager IOManager
        {
            get { return mIOManager; }
        }

        private IntPtr mHandle;
        public IntPtr Handle
        {
            get { return mHandle; }
            //implement Resize()
            set { mHandle = value; }
        }

        int mHeight;
        int mWidth;

        Camera mCamera;
        public Camera Camera
        {
            get { return mCamera; }

        }

        LightManager mLightManager;

        public D3D9Core(IntPtr inHandle, int inWidth, int inHeight)
        {
            Initialize(inHandle, inWidth, inHeight);
            experimentalInit();
        }

        private void Initialize(IntPtr inHandle, int inWidth, int inHeight)
        {
            mHandle = inHandle;
            mHeight = inHeight;
            mWidth = inWidth;
            CreateDriver();
            mCamera = new Camera(this, inWidth, inHeight);
            mIOManager = new IOManager(this);
        }

        //TODO : 記得要把試誤補回去
		internal bool CreateDriver()
		{
			mD3D = new SlimDX.Direct3D9.Direct3D();

			DisplayMode mode = mD3D.GetAdapterDisplayMode(0);

			PresentParameters presentParameters = new PresentParameters();
			presentParameters.AutoDepthStencilFormat = Format.D24X8;
			presentParameters.BackBufferFormat = mode.Format;
            //presentParameters.BackBufferFormat = Format.Unknown;
			presentParameters.BackBufferCount = 1;
			//Fixed resolution
            presentParameters.BackBufferHeight = mHeight;
            presentParameters.BackBufferWidth = mWidth;

			presentParameters.DeviceWindowHandle =mHandle;
			presentParameters.EnableAutoDepthStencil = true;
			presentParameters.FullScreenRefreshRateInHertz = 0;
			presentParameters.Multisample = MultisampleType.None;
			presentParameters.MultisampleQuality = 0;
			presentParameters.PresentationInterval = PresentInterval.Default;
			presentParameters.PresentFlags = PresentFlags.DiscardDepthStencil;
			presentParameters.SwapEffect = SwapEffect.Discard;
			presentParameters.Windowed = true;

            mD3DDevice = new SlimDX.Direct3D9.Device(mD3D, 0, SlimDX.Direct3D9.DeviceType.Hardware, mHandle, CreateFlags.HardwareVertexProcessing, presentParameters);

            mLightManager = new LightManager(this);
			return true;
        }



        #region Experimental
        //Experimental!
        Entity mExpTeapot;
        Light mEnvironmentLight = new Light();
        Sprite mSprite;
        SlimDX.Direct3D9.Font mFont;

        
        private void experimentalInit()
        {
            mExpTeapot = new SphereEntity(this);
            mExpTeapot.Position = new Vector3(0, 0, 0);
 
            Material material = new Material();
            material.Diffuse = Color.LawnGreen;
            material.Ambient = Color.Gray;
            //material.Emissive = Color.LawnGreen;
            mD3DDevice.Material = material;

            //mEnvironmentLight = new Light();
            mEnvironmentLight.Direction = new Vector3(0, 0, 1);
            mEnvironmentLight.Type = LightType.Directional;
            mEnvironmentLight.Diffuse = new Color4(0.8f, 0.2f, 0.6f);
 
            mD3DDevice.SetRenderState(RenderState.Lighting, true);
            mD3DDevice.SetLight(0, mEnvironmentLight);
            mD3DDevice.EnableLight(0, true);


            mSprite = new Sprite(D3DDevice);

            mFont = new SlimDX.Direct3D9.Font(D3DDevice, 18, 9, FontWeight.Light, 0, false, CharacterSet.Default,
                Precision.Default, FontQuality.ClearTypeNatural, PitchAndFamily.DontCare, "");

            OnRender += new Render(experimentalRender);


        }

        void experimentalRender(double inDelta)
        {
            mSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
            int FPS = (int)(1.0 / inDelta);
            mFont.DrawString(mSprite, "FPS : " + FPS.ToString() + " At = " + mCamera.At.ToString() ,0, 0, new Color4(1, 1, 1));
            mSprite.End();


            mExpTeapot.Rotation -= new Vector3(0.00f, 1.57f * (float)inDelta, 0.00f);
            mExpTeapot.Render();
 
        }
        #endregion Experimental



        public bool Update(double inDelta)
        {
            if (OnPreRender != null)
                OnPreRender(inDelta);

            mD3DDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer, new Color4(1, 0.1f, 0.1f, 0.1f), 1.0f, 0);

            mD3DDevice.BeginScene();


            mCamera.Update(inDelta);

            if (OnRender != null)
                OnRender(inDelta);


            mD3DDevice.EndScene();
            mD3DDevice.Present();

            if (OnPostRender != null)
                OnPostRender(inDelta);

            
            return true;
        }
	}
}
